package com.jerry.usbserial.util.task.udp

import android.util.Log
import com.jerry.usbserial.util.*
import java.io.File
import java.io.FileInputStream
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.net.SocketTimeoutException
import kotlin.math.ceil

/**
 * Created by dugang on 2020/7/7.
 */
class UDPMiddleTask(host: String, private val mMiddleFile: File) : Thread() {
    companion object {
        private const val CLIENT_PORT = 9527
        private const val SERVER_PORT = 5021
        private const val RECEIVE_SIZE = 34
        private const val TAG = "UDPMiddleTask"
    }

    private val mServer: String = host.substring(0, host.lastIndexOf(".") + 1) + "255"
    private val mSocketClient = DatagramSocket(CLIENT_PORT).apply { soTimeout = 2000 }

    private val mMiddleInputStream: FileInputStream by lazy { FileInputStream(mMiddleFile) }
    private var mMiddlePackageSize = 0
    private var mMiddlePackageIndex = 0

    private var mDelSpaceSendCount = 0
    private var mPackage0SendCount = 0


    private var processListener: ((process: Int) -> Unit)? = null
    private var resultListener: ((msg: String) -> Unit)? = null

    @Volatile
    private var mCancel = false

    @Volatile
    private var mRetry = 0

    fun cancel() {
        mCancel = true
    }

    fun setOnProcessListener(func: (process: Int) -> Unit) {
        processListener = func
    }

    fun setOnResultListener(func: (msg: String) -> Unit) {
        resultListener = func
    }

    override fun run() {
        delSpace()
        Log.d(TAG, "发送第1次启动命令")


        while (!mCancel) {
            try {
                val packet = DatagramPacket(ByteArray(RECEIVE_SIZE),
                    RECEIVE_SIZE
                )
                mSocketClient.receive(packet)
                val receiveInfo = packet.data ?: ByteArray(RECEIVE_SIZE) { 0 }
                if (receiveInfo.contentEquals("53656E6420546F2055617274204F6B210A0000000000000000000000000000000000".hexToByteArray())) {
                    mRetry = 0
                    if (mDelSpaceSendCount < 1) {
                        mDelSpaceSendCount++
                        sleep(3000)
                        Log.d(TAG, "发送第2次启动命令")
                        delSpace()
                    } else {
                        if (mMiddlePackageSize == 0 && mPackage0SendCount < 2) {
                            mPackage0SendCount++
                            Log.d(TAG, "固件升级,第 0 个包,第${mPackage0SendCount}次发送")
                            sendMiddleFile()
                        } else {
                            mMiddlePackageIndex++
                            processListener?.invoke(mMiddlePackageIndex * 100 / mMiddlePackageSize)

                            when {
                                mMiddlePackageIndex < mMiddlePackageSize -> {
                                    Log.d(TAG, "固件升级,发送第${mMiddlePackageIndex}个包")
                                    sendMiddleFile()
                                }
                                else -> {
                                    val buf = "AE5AA50010A0040102030405010203040506B1030000FFE11E".hexToByteArray()
                                    Log.d(TAG, "固件包发送完毕,发送重启命令")
                                    mSocketClient.send(DatagramPacket(buf, buf.size, InetAddress.getByName(mServer),
                                        SERVER_PORT
                                    ))
                                    mCancel = true
                                    resultListener?.invoke("更新完成,设备重启中...")
                                }
                            }
                        }
                    }
                }
            } catch (e: SocketTimeoutException) {
                if (mRetry < 3) {
                    mRetry++
                    if (mDelSpaceSendCount < 1) {
                        Log.d(TAG, "发送第${mDelSpaceSendCount + 1}次启动命令时,设备响应超时,第 $mRetry 次重试")
                        delSpace()
                    } else {
                        Log.d(TAG, "发送第${mMiddlePackageIndex + 1}个固件包时,设备响应超时,第 $mRetry 次重试")
                        sendMiddleFile()
                    }
                } else {
                    mCancel = true
                    resultListener?.invoke("设备响应超时,更新失败!")
                }
            }
        }
        mSocketClient.close()
    }

    private fun delSpace() {
        val cmdList = mutableListOf<Byte>()
        cmdList.addAll("AE5AA50010A0040102030405010203040506B101".hexToByteArray().toList())
        mMiddlePackageSize = ceil(mMiddleFile.length() / 128f).toInt()
        cmdList.addAll(mMiddlePackageSize.to2HByteArray().toList())
        cmdList.addAll("FFE11E".hexToByteArray().toList())

        val buf = cmdList.toByteArray()
        mSocketClient.send(DatagramPacket(buf, buf.size, InetAddress.getByName(mServer),
            SERVER_PORT
        ))
    }

    private fun sendMiddleFile() {
        sleep(200)
        // 固定头
        val cmdList = mutableListOf<Byte>()
        cmdList.addAll("AE5AA50093A004A51270D013010203040506B102".hexToByteArray().toList())
        // 数据包序号
        cmdList.addAll(mMiddlePackageIndex.to2HByteArray().toList())
        // 数据
        val datas = ByteArray(128)
        mMiddleInputStream.read(datas)
        val dataArray = datas.copyInto(128, 0xFF)
        cmdList.addAll(dataArray.toList())
        //crc
        val crc = CRCUtil.getCrc16(cmdList.toByteArray(), cmdList.size)
        cmdList.addAll(crc.to2HByteArray().toList())
        //固定尾
        cmdList.addAll("FFFFE11E".hexToByteArray().toList())

        val buf = cmdList.toByteArray()
        mSocketClient.send(DatagramPacket(buf, buf.size, InetAddress.getByName(mServer),
            SERVER_PORT
        ))
    }
}